package wxpay

import (
	"bgs/db"
	sqlc "bgs/db/sqlc"
	nsqpUtil "bgs/nsqp/util"
	activityService "bgs/service/activity"
	brandService "bgs/service/brand"
	ledgerService "bgs/service/ledger"
	orderService "bgs/service/order"
	paymentService "bgs/service/payment"
	spokesmanService "bgs/service/spokesman"
	userService "bgs/service/user"
	"bgs/util"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/nsqio/go-nsq"
	"go.uber.org/zap"
	"strconv"
)

// var (
// 	lastPaySuccessNotification *PaySuccessNotification = nil
// )

// PaySuccessNotification 支付成功通知参数
type PaySuccessNotification struct {
	// 商户ID (本地brand_id的映射sg_id)
	BrandID string `json:"brand_id"`
	// 服务商公众号ID
	AppID string `json:"app_id"`
	// 服务商户号
	MchID string `json:"mch_id"`
	// 二级商户公众号ID
	SubAppID string `json:"sub_app_id"`
	// 二级商户号
	SubMchID string `json:"sub_mch_id"`
	// 商户订单号
	OutTradeNo string `json:"out_trade_no"`
	// 微信支付订单号
	TransactionID string `json:"transaction_id"`
	// 交易类型
	TradeType string `json:"trade_type"`
	// 交易状态
	TradeState string `json:"trade_state"`
	// 交易状态描述
	TradeStateDesc string `json:"trade_state_desc"`
	// 附加数据
	Attach string `json:"attach"`
	// 支付完成时间
	SuccessTime string `json:"success_time"`

	// 消息时间戳
	Timestamp int64 `json:"timestamp"`

	// 服务费率 * 10000
	ServiceRate int64 `json:"service_rate"`
	// 服务费
	ServiceFee int64 `json:"service_fee"`
}

// TradePayedHandler wxpay trade message handler
type TradePayedHandler struct {
	dao              *db.PgDao
	slog             *zap.SugaredLogger
	topic            string
	failover         *nsqpUtil.NsqFailover
	activityService  *activityService.ActivityServiceImp
	brandService     *brandService.BrandServiceImp
	ledgerService    *ledgerService.LedgerServiceImp
	orderService     *orderService.OrderServiceImp
	paymentService   *paymentService.PaymentServiceImp
	spokesmanService *spokesmanService.SpokesmanServiceImp
	userService      *userService.UserServiceImp
}

// NewTradePayedHandler create a new handler for trade payed
func NewTradePayedHandler(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	topic string,
	failover *nsqpUtil.NsqFailover,
	activityService *activityService.ActivityServiceImp,
	brandService *brandService.BrandServiceImp,
	ledgerService *ledgerService.LedgerServiceImp,
	orderService *orderService.OrderServiceImp,
	paymentService *paymentService.PaymentServiceImp,
	spokesmanService *spokesmanService.SpokesmanServiceImp,
	userService *userService.UserServiceImp,
) *TradePayedHandler {
	return &TradePayedHandler{
		dao:              pgdao,
		slog:             slog.With("nsq_consumer_handler", "TradePayedHandler"),
		topic:            topic,
		failover:         failover,
		activityService:  activityService,
		brandService:     brandService,
		ledgerService:    ledgerService,
		orderService:     orderService,
		paymentService:   paymentService,
		spokesmanService: spokesmanService,
		userService:      userService,
	}
}

// HandleMessage implements the Handler interface.
func (h *TradePayedHandler) HandleMessage(m *nsq.Message) error {
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	h.slog.Infof("message=>%s", string(m.Body))

	v := &PaySuccessNotification{}
	if decodeErr := json.NewDecoder(bytes.NewReader(m.Body)).Decode(v); decodeErr != nil {
		return fmt.Errorf("无法解析消息[PaySuccessNotification]: %s", decodeErr.Error())
	}

	// if lastPaySuccessNotification != nil && lastPaySuccessNotification.Timestamp >= v.Timestamp {
	// 	h.slog.Infof("过时的消息: lastPaySuccessNotification.Timestamp:%v,v.Timestamp:%v", lastPaySuccessNotification.Timestamp, v.Timestamp)
	// 	return nil
	// }
	reqID := strconv.FormatInt(v.Timestamp, 10)
	slog := h.slog.With("reqID", reqID)
	// 将来抽象到对应的业务组件
	ctx := context.WithValue(context.Background(), util.RequestID{}, reqID)

	var err error
	defer h.failover.BackupSubMsgWhenHandleFail(ctx, &err, nsqpUtil.BackupSubMsgParam{
		Ts:    v.Timestamp,
		Topic: h.topic,
		Mbody: m.Body,
	})

	orderSerialNumber := v.OutTradeNo
	payed, err := util.StringfToGoTime(v.SuccessTime, util.LayoutSecondWithTimeZoneAndT)
	if err != nil {
		return err
	}
	var order sqlc.Order

	err = h.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err = q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return
		}
		if order.OrderStatus != string(sqlc.EmOrderStatusPending) {
			slog.Infof("x0 tradePayedHandler-message is precessed so skip...")
			return
		}

		slog.Infof("a tradePayedHandler-获取订单 ok")
		orderID := order.ID

		payment, err := q.GetPaymentByOrderSerialNumber(ctx, order.SerialNumber)
		if err != nil {
			return
		}
		slog.Infof("aa tradePayedHandler-获取支付单 ok")

		needProfitShare := h.orderService.NeedProfitShare(&order)
		var platformCommission, distributorCommission, bonusAmount uint64
		var orderDetailPtrs []*sqlc.OrderDetail
		if needProfitShare {
			orderDetailPtrs, err = h.orderService.ListOrderDetailPtrsByOrderID(ctx, q, orderID)
			if err != nil {
				return
			}
			slog.Infof("a2 tradePayedHandler-获取订单明细 ok")

			calculateOrderParamPtr := &orderService.CalculateOrderParam{
				OrderPtr:        &order,
				OrderDetailPtrs: orderDetailPtrs,
			}

			if order.NeedProfitToDistributeCommission {
				platformCommission, err = h.orderService.CalculatePlatformCommission(ctx, q, calculateOrderParamPtr)
				if err != nil {
					return
				}
				if platformCommission > 0 {
					slog.Infof("bbb1 tradePayedHandler-计算订单平台佣金(%d ok", platformCommission)
				} else {
					slog.Infof("bbb3 tradePayedHandler-计算订单平台佣金 但是目前是0")
				}
			} else {
				slog.Infof("bbb2 tradePayedHandler-无须计算订单平台佣金 ok")
			}
			if order.NeedProfitToDistributeCommission {
				distributorCommission, err = h.orderService.CalculateDistributorCommission(ctx, q, calculateOrderParamPtr)
				if err != nil {
					return
				}
				slog.Infof("bb1 tradePayedHandler-计算分销订单佣金 ok")
			} else {
				slog.Infof("bb2 tradePayedHandler-无须计算分销订单佣金 ok")
			}

			if order.NeedProfitToBonus {
				bonusAmount, err = h.orderService.CalculateBonus(ctx, q, calculateOrderParamPtr)
				if err != nil {
					return
				}
				slog.Infof("bc1 tradePayedHandler-计算推广订单奖励金 ok")
			} else {
				slog.Infof("bc2 tradePayedHandler-无须计算推广订单奖励金 ok")
			}

			// todo: 目前 platformCommission强制为0,将来看是每笔订单都收还是仅对分账单收
			profitAmount := platformCommission + distributorCommission + bonusAmount

			if profitAmount > 0 {
				// 需要分账的金额(推广订单奖励金+分销订单佣金) >0
				err = h.ledgerService.UpsertRequest(ctx, q, ledgerService.UpsertRequestParam{
					OrderPtr:              &order,
					PaymentAmount:         payment.Amount,
					PlatformCommission:    int64(platformCommission),
					DistributorCommission: int64(distributorCommission),
					BonusAmount:           int64(bonusAmount),
				})
				if err != nil {
					return
				}
				slog.Infof("c tradePayedHandler-新建/更新分账请求 ok")
			} else {
				slog.Infof("c tradePayedHandler-需要分账的金额(佣金)=0,无须分账 ok")
			}
		}

		order, err = h.paymentService.DoAfterPaymentSuccess(ctx, q, paymentService.AfterPaymentSuccessParam{
			PaymentPtr:            &payment,
			Payed:                 payed,
			TransactionNo:         v.TransactionID,
			BonusAmount:           bonusAmount,
			DistributorCommission: distributorCommission,
			WxpayCommissionAmount: v.ServiceFee,
			PlatformCommission:    platformCommission,
		})
		if err != nil {
			return
		}
		slog.Infof("d tradePayedHandler-支付成功DoAfterPaymentSuccess ok")

		err = h.brandService.LoggingAccountForOrder(ctx, q, &order)
		if err != nil {
			return
		}
		slog.Infof("e tradePayedHandler-订单支付成功后商家记账成功 ok")

		err = h.orderService.MarkOrderAccounted(ctx, q, order.ID)
		if err != nil {
			return
		}
		slog.Infof("g tradePayedHandler-标记订单已记账 ok")

		err = h.activityService.UpdateActivityOrderStatSinceOrderPayed(ctx, q, &order)
		if err != nil {
			return
		}
		slog.Infof("h tradePayedHandler-支付成功的订单统计到(ActivityOrderStat) ok")

		err = h.activityService.UpdateActivityUserOrderStatSinceOrderPayed(ctx, q, &order)
		if err != nil {
			return
		}
		slog.Infof("i tradePayedHandler-支付成功的订单统计到(ActivityUserOrderStat) ok")

		err = h.userService.UpdateStatSinceOrderPayed(ctx, q, &order)
		if err != nil {
			return
		}
		slog.Infof("j tradePayedHandler-支付成功的订单统计到(UserStat) ok")

		err = h.orderService.MarkOrderCounted(ctx, q, order.ID)
		if err != nil {
			return
		}
		slog.Infof("k tradePayedHandler-标记订单已被统计 ok")

		err = h.activityService.UpdateActivitySkuFreezeQuantityAndAvailableQuantitySinceOrderPayedWithLock(ctx, q, &order)
		if err != nil {
			return
		}
		slog.Infof("l tradePayedHandler-支付成功的更新到(ActivitySku) ok")

		if order.SpokesmanID.Valid {
			err = h.spokesmanService.UpdateSaleAmountSinceOrderPayed(ctx, q, &order)
			if err != nil {
				return
			}
			slog.Infof("m tradePayedHandler-支付成功的更新到(Spokesman) ok")
		}

		if order.OrderType == string(sqlc.EmOrderTypeRedeemAward) {
			err = h.activityService.UpdateUserAwardSinceRedeemAwardOrderPayed(ctx, q, &order)
			if err != nil {
				return
			}
			slog.Infof("n tradePayedHandler-支付成功的更新到(ActivityUserAward) ok")
		}

		return
	})
	if err != nil {
		return err
	}
	slog.Infof("消息[PaySuccessNotification]处理成功")

	// lastPaySuccessNotification = v
	// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
	return nil
}
